#pragma once

#include <NTL/ZZ.h>
#include <NTL/ZZ_pX.h>
#include <NTL/ZZ_pE.h>
#include <NTL/vec_ZZ_pE.h>
#include <NTL/ZZ_pXFactoring.h>
#include <NTL/ZZ_pEX.h>
#include <NTL/mat_ZZ.h>

NTL_CLIENT

typedef struct remainderZZ{
	ZZ divisor;
	ZZ residual;
}remainderZZ;

 

static class Utils
{
public:
	Utils(void);
	~Utils(void);
	ZZ fastExp(const ZZ& a, const ZZ& e, const ZZ& n);
	ZZ fastExpPolynomials(const ZZ_pEX& a, const ZZ_pEX& e, const ZZ_pEX& n);
	ZZ rhoPollard(const ZZ &n, ZZ_pX &f);
	ZZ rhoPollardOptimizado(const ZZ &n, ZZ_pX &f, int numProductos);
	ZZ factorizacionFermat(const ZZ &n);
	long primeTestRabinMiller(const ZZ& n, long t);
	int showMenu(void);
	ZZ_pEX EEAPolynomials(const ZZ_pEX var1, const ZZ_pEX var2, ZZ_pEX& result1, ZZ_pEX& result2);  
	ZZ EEA(const ZZ var1, const ZZ var2, ZZ& result1, ZZ& result2);
	ZZ rhoPollardRa(const ZZ &n, ZZ_pX &f);
	int getCRT ( void );
	remainderZZ* getData ( int const * const num );
    // ZZ cRT ( remainderZZ * arr, int const * const num );
	ZZ cRT ( remainderZZ * arr, int num );
	ZZ CRTsegunClase(remainderZZ * arr, int* num );
	ZZ babyStep(const ZZ &n, ZZ &alfa, ZZ &beta);
	ZZ Pohlig_Hellman(const ZZ &base, const ZZ &num, const ZZ &p, ZZ_pX &f);
	ZZ Pohlig_HellmanConBabyStep(const ZZ &base, const ZZ &num, const ZZ &p, ZZ_pX &f);
	ZZ elGamal(ZZ m, long n);
	ZZ descifrarGamal(ZZ p, ZZ g, ZZ A, ZZ a, ZZ y1, ZZ y2);
	void firmaElGamal(ZZ m, long n);
	bool comprobarFirma(ZZ A,ZZ g, ZZ p, ZZ M, ZZ R, ZZ S);
	ZZ textToZZ(char *text,int longitud);
	string ZZToText(const ZZ &a);
	ZZ elevarA(const ZZ &b, const ZZ &e);
	bool comprobarPohligHellman(const ZZ &base, const ZZ &p, vec_ZZ &descomposicion);

private:
	long checkForm(const ZZ& n, const ZZ& x);
	bool esCuadrado(const ZZ &n);
	ZZ lcm ( ZZ a, ZZ b );
	ZZ mult(remainderZZ * arr, int i, int const * const num);	
};
